fix: don't cache the 'en' language fallback on anonymous pages (#41618)#41663
fix: don't cache the 'en' language fallback on anonymous pages (#41618)#41663DeepDiver1975 wants to merge 2 commits into
Conversation
b966006 to
73948ad
Compare
Anonymous pages (login page, password-protected public share page) always rendered in English even when default_language was set or the browser sent a matching Accept-Language header, while authenticated pages were translated correctly. Root cause: OC\L10N\Factory is a per-request singleton. When the first no-app findLanguage() ran without a usable Accept-Language match (e.g. the header not forwarded by the web server), setLanguageFromRequest() cached the 'en' last-resort fallback in $requestLanguage. findLanguage() short-circuits on a non-empty $requestLanguage (languageExists(_, 'en') is always true), so every later lookup returned 'en' before default_language or Accept-Language could be consulted. Authenticated requests are unaffected because they seed $requestLanguage from the stored user language first. Stop caching the 'en' fallback so default_language and Accept-Language are re-evaluated on subsequent lookups. The FactoryTest data rows that enshrined the 'en' caching are updated to assert the fallback is returned but not stored. Fixes #41618 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Thomas Müller <1005065+DeepDiver1975@users.noreply.github.com>
73948ad to
efdbe72
Compare
Code ReviewOverviewFixes #41618 where anonymous pages (login, public-share password page) always render in English despite a configured Correctness — soundTraced the full
Style / conventions — good
Test coverage — one gap worth closingThe revised However, no test reproduces the actual reported bug end-to-end: two sequential Recommend adding a Performance — negligible
Security — noneNo auth, input-handling, or output-encoding surface touched. VerdictClean, minimal, correctly-reasoned fix. Approve, with the recommended end-to-end |
Reproduces the two-call scenario the fix targets: on an anonymous request the first no-app findLanguage() falls through to the 'en' last-resort fallback (no Accept-Language match, no default_language). This must not poison the per-request Factory singleton, so a later findLanguage() honors default_language instead of short-circuiting on a cached 'en'. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Thomas Müller <1005065+DeepDiver1975@users.noreply.github.com>
Re-review — after applying the recommended testPushed What was added
This locks in the fix at the layer where the bug actually manifested. On the pre-fix code, step 4 would return Verification
The earlier test-coverage gap is now closed. No other findings — the fix and its tests look complete. Approve. |
dj4oC
left a comment
There was a problem hiding this comment.
Fixes #41618 — anonymous pages (login / public-share password page) now honor default_language and Accept-Language instead of always rendering in English, by no longer caching the 'en' last-resort fallback in the per-request L10N\Factory singleton.
Branch target
oC11 / master — in scope. ✓
Review passes
- Security: no findings. Pure i18n language-selection logic; no user input reaches a sink and there is no authz / path-traversal / injection surface. (OWASP/CWE: n/a.)
- Stability: no findings. Removing the
$this->requestLanguage = 'en'assignment leavesrequestLanguageempty on the last-resort path, so a laterfindLanguage()re-evaluatesdefault_language(step 3) thenAccept-Language(step 4). The method still returns'en', so callers that don't re-query are unaffected — no BC break. PHP 8.3-clean (no 7.4-only idioms reintroduced). - Performance: no finding of concern. Anonymous requests with no matchable language now re-run the (in-memory, DB-free) resolution on each lookup rather than short-circuiting on a cached
'en'. Negligible; introduces no new queries. - Test coverage: the changed line is directly exercised — new regression test
testFindLanguageDoesNotCacheFallbackAcrossAnonymousLookups()plus the updateddataSetLanguageFromRequestrows assert the fallback is returned ('en') but not cached (requestLanguagestays''). Verified independently rather than from the PR text: PHP Unit is green on sqlite / mariadb 10.6 & 10.11 / mysql 8.0 / postgres.
Quality gates
- Security: no findings
- Stability: no findings
- Performance: no findings
- Test coverage: PHPUnit regression added; changed lines covered; PHP Unit CI green on all 5 DB engines
- TODOs found: none
- Dependency touched: no
- CI status: all green
- Stale review: no
Note (non-blocking)
This changes a user-visible frontend behavior (the rendered language of the login and public-share pages). Unit coverage of the defect itself is solid, but there is no end-to-end / acceptance guard that an anonymous page actually renders in default_language. A follow-up acceptance-level check would close that gap — not blocking, given the regression unit test and green CI.
Verdict
Commenting — no blocking findings. Requires one human approval before merge per repo policy.
🤖 Automated review by Claude Code (security · stability · performance · coverage)
Generated by Claude Code
Problem
Anonymous pages — the login page and the password-protected public-share page — always render in English, even when
default_languageis configured or the browser sends a matchingAccept-Languageheader. Authenticated pages render in the correct language. Fixes #41618.Root cause
OC\L10N\Factoryis a per-request singleton.findLanguage()short-circuits on a non-empty$requestLanguage(andlanguageExists(_, 'en')is always true). When the first no-appfindLanguage()runs without a usableAccept-Languagematch — e.g. the header isn't forwarded by the web server, as in the official Docker/Apache image —setLanguageFromRequest()caches the'en'last-resort fallback into$requestLanguage:Every later lookup on that request then returns
'en'beforedefault_language(step 3) orAccept-Language(step 4) is ever consulted. Authenticated requests are unaffected because they seed$requestLanguagefrom the stored user language first.The original triage hypothesis (guest layout not consulting
findLanguage()) was refuted while tracing the code —layout.guest.php/TemplateLayoutdo callfindLanguage(); the defect is the poisoned cache.Fix
Stop caching the
'en'fallback insetLanguageFromRequest().default_languageandAccept-Languageare then re-evaluated on subsequent lookups, so anonymous pages honor both. Single-file behavioral change inlib/private/L10N/Factory.php.Tests
tests/lib/L10N/FactoryTest.php: thedataSetLanguageFromRequestrows that previously enshrined the'en'caching (no-app, no available match) now assert the fallback is returned ('en') but not stored (requestLanguagestays'') — which is exactly the regression guard for this bug.Verified locally:
php -lclean on both files. Full suite runs in CI (Test (Linux)).🤖 Generated with Claude Code